8c0f079a516e8fe9c7e98eceb948875a63e4b0ed,governator-core/src/main/java/com/netflix/governator/ScanningModuleBuilder.java,ScanningModuleBuilder,build,#,137
Before Change
// Generate the list of elements here and immediately create a module from them. This ensures
// that the class path is canned only once as a Module's configure method may be called multiple
// times by Guice.
return Elements.getModule(Elements.getElements(new AbstractModule() {
@Override
public void configure() {
for ( String basePackage : packages ) {
try {
String basePackageWithSlashes = basePackage.replace(".", "/");
for (URL url : Collections.list(classLoader.getResources(basePackageWithSlashes))) {
try {
if ( isJarURL(url)) {
String jarPath = url.getFile();
if ( jarPath.contains("!") ) {
jarPath = jarPath.substring(0, jarPath.indexOf("!"));
url = new URL(jarPath);
}
File file = ClasspathUrlDecoder.toFile(url);
try (JarFile jar = new JarFile(file)) {
for (JarEntry entry : Collections.list(jar.entries())) {
try {
if ( entry.getName().endsWith(".class") && entry.getName().startsWith(basePackageWithSlashes)) {
try (InputStream is = jar.getInputStream(entry)) {
handleClass(is);
}
}
} catch (Exception e) {
addError("Unable to scan JarEntry '%s' in '%s'. %s", entry.getName(), file.getCanonicalPath(), e.getMessage());
addError(e);
}
}
} catch (Exception e ) {
addError("Unable to scan '%s'. %s", file.getCanonicalPath(), e.getMessage());
addError(e);
}
} else {
DirectoryClassFilter filter = new DirectoryClassFilter(classLoader);
for ( String className : filter.filesInPackage(url, basePackage) ) {
try (InputStream is = filter.bytecodeOf(className)) {
handleClass(is);
}
}
}
} catch (Exception e) {
addError("Unable to scan jar '%s'. %s ", url, e.getMessage());
addError(e);
}
}
} catch ( Exception e ) {
addError("Classpath scanning failed for package \'" + basePackage + "\'");
addError(e);
}
}
}
private boolean isJarURL(URL url) {
String protocol = url.getProtocol();
return "zip".equals(protocol) || "jar".equals(protocol) ||
("file".equals(protocol) && url.getPath().endsWith(".jar"));
}
private void handleClass(InputStream inputStream) throws IOException {
new ClassReader(inputStream).accept(new ClassVisitor(Opcodes.ASM5) {
private String className;
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
className = name.replace('/', '.');
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
Type type = getType(desc);
if (includeRule.apply(className)) {
for (AnnotatedClassScanner scanner : scanners) {
if (getType(scanner.annotationClass()).equals(type)) {
try {
Class<?> cls = Class.forName(className, false, classLoader);
scanner.applyTo(binder(), cls.getAnnotation(scanner.annotationClass()), Key.get(cls));
} catch (ClassNotFoundException e) {
binder().addError(e);
binder().addError("Failed process scanned class %s", className);
}
}
}
}
return super.visitAnnotation(desc, visible);
}
}, SKIP_CODE);
}
}));
};
}
After Change
// Generate the list of elements here and immediately create a module from them. This ensures
// that the class path is canned only once as a Module's configure method may be called multiple
// times by Guice.
return Elements.getModule(Elements.getElements(new AbstractModule() {
@Override
public void configure() {
final ClassPath classPath;
try {
classPath = ClassPath.from(classLoader);
} catch (IOException e) {
this.addError(e);
return;
}
for (ClassInfo classInfo : classPath.getAllClasses()) {
if (!isInTargetPackages(classInfo.getPackageName()) || !includeRule.apply(classInfo.getName())) {
continue;
}
for (AnnotatedClassScanner scanner : scanners) {
Class<?> cls = classInfo.load();
if (cls.isAnnotationPresent(scanner.annotationClass())) {
try {
scanner.applyTo(binder(), cls.getAnnotation(scanner.annotationClass()), Key.get(cls));
} catch (Exception e) {
binder().addError("Failed process scanned class %s", classInfo.getName());
binder().addError(e);
}
}
}
}
}
}));
};
}